import { Layout } from '@/layout';

export const meta = {
  title: 'How can I add dynamic CSS styles?',
  description: 'Use data attributes, CSS variables or inline styles',
  slug: 'dynamic-css-styles',
  category: 'styles',
  tags: ['dynamic', 'CSS', 'styles'],
  created_at: 'January 4, 2024',
  last_updated_at: 'January 4, 2024',
};

export default Layout(meta);

## data- attributes

If the value that controls dynamic styles is a boolean or a known small union of values,
use [data- attributes](https://mantine.dev/styles/data-attributes/).

First, define data- attributes on the component. In the example below:

- `data-disabled` represents boolean `disabled` attribute. `disabled || undefined` is required
  to not add `data-disabled="false"` attribute when `disabled` is `false` and allow styling with `&[data-disabled]` selector.
- `data-orientation` represents `orientation` prop which can be either `horizontal` or `vertical`.
  In styles you can reference it with `&[data-orientation="horizontal"]` selector.

```tsx
import { Box } from '@mantine/core';
import classes from './Demo.module.css';

interface DemoProps {
  disabled: boolean;
  orientation: 'horizontal' | 'vertical';
}

function Demo({ disabled, orientation }: DemoProps) {
  return (
    <Box
      data-disabled={disabled || undefined}
      data-orientation={orientation}
      className={classes.root}
    >
      My demo
    </Box>
  );
}
```

Then add styles in `.module.css` file:

```scss
.root {
  background: orange;
  display: flex;

  &[data-disabled] {
    background: silver;
  }

  &[data-orientation='horizontal'] {
    flex-direction: row;
  }

  &[data-orientation='vertical'] {
    flex-direction: column;
  }
}
```

## Inline styles

If the value that controls dynamic styles is not represented by a known union
of values (for example, value can be any valid CSS color), then you can use
inline styles or [style props](https://mantine.dev/styles/style-props/):

```tsx
import { Box } from '@mantine/core';

interface DemoProps {
  fontFamily: string;
  color: string;
}

function Demo({ fontFamily, color }: DemoProps) {
  return (
    <Box style={{ backgroundColor: color }} ff={fontFamily}>
      My demo
    </Box>
  );
}
```

If you need to customize a deeply nested element, use [styles](https://mantine.dev/styles/styles-api/#styles-prop)
prop instead:

```tsx
import { Button } from '@mantine/core';

interface DemoProps {
  color: string;
}

function Demo({ color }: DemoProps) {
  return (
    <Button styles={{ label: { backgroundColor: color } }}>
      My demo
    </Button>
  );
}
```

Note that, it is not possible use pseudo-classes (for example, `:hover`, `:first-of-type`)
and media queries inside the `styles` prop. For this purpose, use CSS variables
with [classNames](https://mantine.dev/styles/styles-api/#classnames-prop) prop.

## CSS variables

If none of the methods above works for you (for example, you want to customize, `:hover`
styles based on component prop), use CSS variables
with [classNames](https://mantine.dev/styles/styles-api/#classnames-prop) prop.

First, define CSS variables in `style` or `styles` prop:

```tsx
import { Box } from '@mantine/core';
import classes from './Demo.module.css';

interface DemoProps {
  color: string;
}

function Demo({ color }: DemoProps) {
  return (
    <Box style={{ '--demo-hover': color }} className={classes.root}>
      My demo
    </Box>
  );
}
```

Then reference them in `.module.css` file:

```scss
.root {
  background: orange;

  &:hover {
    background: var(--demo-hover);
  }
}
```
